04 Writing User Stories for APIs
Introduction
This document provides a specialised framework for writing clear, consistent, and testable user stories for API development in Jira. APIs have unique characteristics that require specific considerations in story writing, including endpoints, request/response formats, authentication, error handling, and integration patterns.
Whether you're a Business Analyst, API Designer, Backend Developer, QA Engineer, or Integration Specialist, this guide will help you create API stories that drive clarity, reduce ambiguity, and ensure robust API implementations.
What You'll Learn
By following this guide, you will learn:
- ✅ How to structure API user stories with API-specific components
- ✅ How to write acceptance criteria for endpoints, methods, and payloads
- ✅ Best practices for API authentication, authorisation, and security
- ✅ How to handle API errors, validation, and edge cases
- ✅ Techniques for documenting request/response contracts
- ✅ How to address API versioning, rate limiting, and performance
- ✅ Templates and examples specific to API development
Key Principles
- Contract-first – Define API contracts clearly before implementation
- Security by design – Authentication and authorisation are not optional
- Error handling – Comprehensive error responses are essential
- Versioning – Plan for API evolution and backward compatibility
- Documentation – API stories must include clear request/response examples
- Testability – ACs must enable both manual and automated API testing
1. Purpose of API User Stories
An API user story expresses a requirement from the perspective of an API consumer (client application, system, or service), describing:
- What API functionality is needed
- Why it is needed
- How it creates value for the consuming system
API user stories differ from UI stories in that they focus on:
- Data exchange rather than user interaction
- System-to-system communication rather than human-computer interaction
- Contract definitions (request/response formats) rather than visual design
- Integration patterns rather than workflow steps
Why API Stories Matter
Well-written API stories:
- Enable integration – Clear contracts allow other systems to integrate effectively
- Reduce integration time – Detailed specifications prevent back-and-forth clarification
- Ensure consistency – Standardised patterns across API endpoints
- Facilitate testing – Testable ACs enable automated API testing
- Support documentation – Stories become the foundation for API documentation
2. Core Structure for API Stories
Each API user story should follow this template:
As a [API consumer role]
I want to [API action/operation]
So that [business value/integration benefit]
Guidelines for Each Line
AS A… (API Consumer Role)
The role represents who or what consumes the API:
- Client applications – "As a mobile application"
- External systems – "As a third-party billing system"
- Internal services – "As a microservice"
- System actors – "As a scheduled batch job"
- API consumers – "As an API client"
Examples:
- ✅ "As a mobile application"
- ✅ "As a third-party integration service"
- ✅ "As a scheduled billing processor"
- ❌ "As a developer" (too vague)
- ❌ "As a user" (APIs don't have direct users)
I WANT… (API Action/Operation)
Describe the API operation clearly:
- Use HTTP method terminology when appropriate
- Focus on the data operation, not implementation
- Be specific about what data is exchanged
Good examples:
- ✅ "I want to retrieve enquiry details by ID"
- ✅ "I want to create a new enquiry via API"
- ✅ "I want to update enquiry status"
- ✅ "I want to search enquiries with filters"
Poor examples:
- ❌ "I want an API endpoint" (too vague)
- ❌ "I want to call the database" (too technical)
- ❌ "I want a REST API" (implementation detail)
SO THAT… (Business Value/Integration Benefit)
Explain why the API is needed:
- Focus on integration benefits
- Describe business value enabled
- Explain system-to-system value
Examples:
- ✅ "So that the mobile app can display enquiry details"
- ✅ "So that external systems can create enquiries automatically"
- ✅ "So that billing systems can retrieve invoice data"
- ✅ "So that real-time status updates can be synchronized"
3. HTTP Methods
Understanding HTTP methods is crucial for designing RESTful APIs. Each method has a specific purpose and semantic meaning that should be respected to ensure API consistency and predictability.
GET
Definition: GET is used to retrieve data from a server. It is a safe and idempotent method, meaning it should not modify server state and can be called multiple times with the same result.
When to Use:
- Retrieving a single resource by ID:
GET /api/v1/enquiries/{id} - Listing multiple resources:
GET /api/v1/enquiries - Searching or filtering resources:
GET /api/v1/enquiries?status=AUTHORISED - Reading data without side effects
Characteristics:
- ✅ Safe – Does not modify server state
- ✅ Idempotent – Multiple identical requests have the same effect
- ✅ Cacheable – Responses can be cached
- ❌ Should not have a request body (though technically allowed)
- ❌ Should not be used for operations that change data
Example:
GET /api/v1/enquiries/12345 HTTP/1.1
Host: api.example.com
Authorisation: Bearer {api_key}
POST
Definition: POST is used to create new resources or perform actions that result in state changes. It is not idempotent – calling it multiple times may create multiple resources.
When to Use:
- Creating a new resource:
POST /api/v1/enquiries - Performing actions that don't fit other methods:
POST /api/v1/enquiries/{id}/complete - Submitting forms or data
- Triggering operations with side effects
Characteristics:
- ❌ Not safe – Modifies server state
- ❌ Not idempotent – Multiple calls may create multiple resources
- ✅ Can have a request body
- ✅ Returns
201 CreatedwithLocationheader for new resources - ✅ Returns
200 OKfor actions without resource creation
Example:
POST /api/v1/enquiries HTTP/1.1
Host: api.example.com
authorisation: Bearer {api_key}
Content-Type: application/json
{
"customerId": "CUST001",
"vehicleRegistration": "AB12 CDE",
"description": "MOT Test"
}
PUT
Definition: PUT is used to replace an entire resource or create it if it doesn't exist. It is idempotent – calling it multiple times with the same data has the same effect.
When to Use:
- Updating an entire resource:
PUT /api/v1/enquiries/{id} - Creating a resource with a specific ID:
PUT /api/v1/enquiries/{id} - Full resource replacement (not partial updates)
Characteristics:
- ❌ Not safe – Modifies server state
- ✅ Idempotent – Multiple identical requests have the same effect
- ✅ Can have a request body
- ✅ Must include all fields (full replacement)
- ✅ Returns
200 OKif resource exists,201 Createdif new resource created
Example:
PUT /api/v1/enquiries/12345 HTTP/1.1
Host: api.example.com
authorisation: Bearer {api_key}
Content-Type: application/json
{
"enquiryId": "12345",
"status": "COMPLETED",
"customerId": "CUST001",
"vehicleRegistration": "AB12 CDE",
"completedAt": "2025-01-15T14:30:00Z"
}
PATCH
Definition: PATCH is used to partially update a resource. It applies modifications to an existing resource without replacing the entire resource. It should be idempotent when possible.
When to Use:
- Partial updates to a resource:
PATCH /api/v1/enquiries/{id} - Updating specific fields without sending the entire resource
- When you only want to change a few fields
Characteristics:
- ❌ Not safe – Modifies server state
- ✅ Should be idempotent (when possible)
- ✅ Can have a request body
- ✅ Only includes fields to be updated
- ✅ Returns
200 OKwith updated resource
Example:
PATCH /api/v1/enquiries/12345 HTTP/1.1
Host: api.example.com
authorisation: Bearer {api_key}
Content-Type: application/json
{
"status": "COMPLETED",
"completedAt": "2025-01-15T14:30:00Z"
}
DELETE
Definition: DELETE is used to remove a resource from the server. It is idempotent – deleting a resource that doesn't exist should still return success (or 404 Not Found).
When to Use:
- Deleting a resource:
DELETE /api/v1/enquiries/{id} - Removing a resource permanently
- Soft deletes (marking as deleted) can also use DELETE
Characteristics:
- ❌ Not safe – Modifies server state
- ✅ Idempotent – Deleting a non-existent resource should be safe
- ❌ Should not have a request body
- ✅ Returns
200 OKor204 No Contenton success - ✅ Returns
404 Not Foundif resource doesn't exist (optional)
Example:
DELETE /api/v1/enquiries/12345 HTTP/1.1
Host: api.example.com
authorisation: Bearer {api_key}
Method Selection Guide
| Operation | Method | Example |
|---|---|---|
| Retrieve single resource | GET | GET /api/v1/enquiries/{id} |
| List resources | GET | GET /api/v1/enquiries |
| Create new resource | POST | POST /api/v1/enquiries |
| Replace entire resource | PUT | PUT /api/v1/enquiries/{id} |
| Partial update | PATCH | PATCH /api/v1/enquiries/{id} |
| Delete resource | DELETE | DELETE /api/v1/enquiries/{id} |
| Action/Operation | POST | POST /api/v1/enquiries/{id}/complete |
💡 Tip: When in doubt between PUT and PATCH, use PATCH for partial updates. Use PUT only when you're replacing the entire resource.
4. HTTP Status Codes
HTTP status codes communicate the result of an API request. Using appropriate status codes is essential for clear API contracts and proper error handling. Status codes are grouped into five categories:
2xx Success
These codes indicate that the request was successfully received, understood, and processed.
200 OK
- Use when: Request succeeded
- Common for: GET, PUT, PATCH requests
- Response: Usually includes response body with data
Example:
200 OK
{
"enquiryId": "12345",
"status": "AUTHORISED"
}
201 Created
- Use when: New resource was successfully created
- Common for: POST requests that create resources
- Response: Should include
Locationheader with URL of new resource - Response body: Usually includes the created resource
Example:
201 Created
Location: /api/v1/enquiries/12345
{
"enquiryId": "12345",
"status": "CREATED"
}
204 No Content
- Use when: Request succeeded but no content to return
- Common for: DELETE requests, or updates that don't need response body
- Response: No response body
Example:
204 No Content
(Empty body)
4xx Client Error
These codes indicate that the client made an error (e.g., bad request, unauthorized, not found).
400 Bad Request
- Use when: Request is malformed or invalid
- Common causes: Missing required fields, invalid data format, validation errors
- Response: Should include error details explaining what's wrong
Example:
400 Bad Request
{
"error": "Bad Request",
"message": "Validation failed",
"code": "VALIDATION_ERROR",
"details": [
{
"field": "customerId",
"message": "customerId is required"
}
]
}
401 Unauthorized
- Use when: Authentication is required or failed
- Common causes: Missing authentication token, invalid credentials, expired token
- Response: Should include
WWW-Authenticateheader
Example:
401 Unauthorized
WWW-Authenticate: Bearer
{
"error": "Unauthorized",
"message": "Valid API key required",
"code": "AUTH_REQUIRED"
}
403 Forbidden
- Use when: Client is authenticated but not authorized for the action
- Common causes: Insufficient permissions, role restrictions
- Difference from 401: Client is authenticated but lacks permission
Example:
403 Forbidden
{
"error": "Forbidden",
"message": "You do not have permission to delete enquiries",
"code": "INSUFFICIENT_PERMISSIONS"
}
404 Not Found
- Use when: Requested resource does not exist
- Common for: GET, PUT, PATCH, DELETE requests for non-existent resources
- Response: Should indicate which resource was not found
Example:
404 Not Found
{
"error": "Not Found",
"message": "Enquiry with ID 99999 not found",
"code": "ENQUIRY_NOT_FOUND"
}
409 Conflict
- Use when: Request conflicts with current state of resource
- Common causes: Duplicate creation, version conflicts, concurrent modifications
- Response: Should explain the conflict
Example:
409 Conflict
{
"error": "Conflict",
"message": "Enquiry with this ID already exists",
"code": "DUPLICATE_ENQUIRY"
}
422 Unprocessable Entity
- Use when: Request is well-formed but semantically incorrect
- Common causes: Business rule violations, logical errors
- Difference from 400: Request syntax is valid but business logic fails
Example:
422 Unprocessable Entity
{
"error": "Unprocessable Entity",
"message": "Cannot complete enquiry in current status",
"code": "INVALID_STATUS_TRANSITION"
}
429 Too Many Requests
- Use when: Client has exceeded rate limit
- Response: Should include
Retry-Afterheader indicating when to retry - Response: Should include rate limit headers (
X-RateLimit-*)
Example:
429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1640995200
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Please retry after 60 seconds",
"code": "RATE_LIMIT_EXCEEDED"
}
5xx Server Error
These codes indicate that the server encountered an error and could not fulfill the request.
500 Internal Server Error
- Use when: Unexpected server error occurred
- Common causes: Unhandled exceptions, database errors, system failures
- Response: Should not expose internal implementation details
- Note: Should be logged for investigation
Example:
500 Internal Server Error
{
"error": "Internal Server Error",
"message": "An unexpected error occurred",
"code": "INTERNAL_ERROR",
"requestId": "req-12345"
}
502 Bad Gateway
- Use when: Server acting as gateway received invalid response from upstream server
- Common causes: Upstream service unavailable, timeout, invalid response
- Use in: API gateway or proxy scenarios
Example:
502 Bad Gateway
{
"error": "Bad Gateway",
"message": "Upstream service unavailable",
"code": "UPSTREAM_ERROR"
}
503 Service Unavailable
- Use when: Server is temporarily unavailable
- Common causes: Maintenance, overload, temporary outage
- Response: Should include
Retry-Afterheader if known
Example:
503 Service Unavailable
Retry-After: 300
{
"error": "Service Unavailable",
"message": "Service is temporarily unavailable. Please retry later",
"code": "SERVICE_UNAVAILABLE"
}
504 Gateway Timeout
- Use when: Server acting as gateway did not receive timely response from upstream
- Common causes: Upstream service timeout, slow response
- Use in: API gateway or proxy scenarios
Example:
504 Gateway Timeout
{
"error": "Gateway Timeout",
"message": "Upstream service did not respond in time",
"code": "UPSTREAM_TIMEOUT"
}
Status Code Selection Guide
| Scenario | Status Code | Method |
|---|---|---|
| Successfully retrieved resource | 200 | GET |
| Successfully created resource | 201 | POST |
| Successfully updated resource | 200 or 204 | PUT, PATCH |
| Successfully deleted resource | 200 or 204 | DELETE |
| Invalid request format | 400 | Any |
| Missing/invalid authentication | 401 | Any |
| Insufficient permissions | 403 | Any |
| Resource not found | 404 | GET, PUT, PATCH, DELETE |
| Resource conflict | 409 | POST, PUT, PATCH |
| Validation failed | 422 | POST, PUT, PATCH |
| Rate limit exceeded | 429 | Any |
| Server error | 500 | Any |
| Service unavailable | 503 | Any |
💡 Tip: Always include an error response body with 4xx and 5xx status codes. Include an error code, human-readable message, and optionally request ID for tracing.
5. Summary Section
The Summary Section for API stories provides brief bullet points that summarize what the API endpoint will deliver. It acts as a quick reference for developers, testers, and stakeholders to understand the intent of the story without reading the full acceptance criteria.
This section should answer the question:
"What will be different once this API endpoint is delivered?"
Purpose of the Summary Section
- Communicates API intent at a glance
- Helps reviewers quickly understand scope
- Supports faster refinement and estimation
- Reduces misinterpretation of detailed acceptance criteria
- Acts as a sanity check before development begins
Guidelines for Writing the Summary
- Use simple, non-technical language
- Focus on outcomes, not implementation
- Keep each bullet point brief and clear
- Use bullet points (not numbered lists)
- Avoid edge cases and exceptions (covered in ACs)
- Typically include 3–6 high-level bullet points
- Ensure alignment with the As a / I want / So that statement
What to Include in Summary
The Summary should include brief bullet points covering:
- API endpoint – HTTP method and endpoint path
- Primary functionality – What the API does
- Authentication/authorisation – Security requirements
- Key data operations – What data is exchanged
- Integration context – Who consumes this API
- Important constraints – Rate limits, versioning, etc.
What to Avoid
- Technical design or solution details
- Database or infrastructure specifics
- Error handling scenarios (covered in Acceptance Criteria)
- Overlapping or duplicate points
- Detailed request/response structures (covered in API Contract)
Example Summary
- Create GET endpoint
/api/v1/enquiries/{id}to retrieve enquiry details - Implement authentication using API key
- Return enquiry data in JSON format with standard structure
- Handle not found (404) and unauthorized (401) errors
- Support integration with mobile application and third-party systems
Quality Checklist
A good summary should:
- Be readable in under 30 seconds
- Clearly describe the API endpoint and its purpose
- Match the acceptance criteria
- Contain no technical jargon
- Reflect business/integration intent
Analyst Tip
If the summary cannot be clearly written in 3–6 bullet points, the story is likely:
- Too large
- Poorly defined
- Missing clarity
In such cases, revisit the scope or split the story before refinement.
6. Acceptance Criteria for APIs
API acceptance criteria must cover:
- Request validation – Input validation and error responses
- Response format – Structure, status codes, headers
- Authentication/authorisation – Security validation
- Error handling – All error scenarios
- Edge cases – Boundary conditions, null handling
- Performance – Response times, throughput
BDD Format for APIs
| Keyword | Purpose | API Example |
|---|---|---|
| Given | Preconditions or API state | "Given an enquiry exists with ID 12345" |
| When | API request is made | "When a GET request is made to /api/v1/enquiries/12345" |
| Then | Expected API response | "Then the API returns status 200 with enquiry JSON" |
| And | Additional conditions | "And the response includes all required fields" |
API-Specific AC Patterns
Successful Request
Given an enquiry exists with ID 12345
And the API client has valid authentication
When a GET request is made to /api/v1/enquiries/12345
Then the API returns status code 200
And the response body contains enquiry data in JSON format
And the response includes Content-Type: application/json header
Authentication Failure
Given an API request is made
When the request does not include a valid API key
Then the API returns status code 401
And the response body contains error message "Unauthorized"
And the response includes WWW-Authenticate header
Resource Not Found
Given no enquiry exists with ID 99999
And the API client has valid authentication
When a GET request is made to /api/v1/enquiries/99999
Then the API returns status code 404
And the response body contains error message "Enquiry not found"
Validation Error
Given the API client has valid authentication
When a POST request is made to /api/v1/enquiries
And the request body is missing required field "customerId"
Then the API returns status code 400
And the response body contains validation error details
And the error includes field name and error message
Rate Limiting
Given the API client has made 100 requests in the last minute
And the rate limit is 100 requests per minute
When another request is made
Then the API returns status code 429
And the response includes Retry-After header
And the response body indicates rate limit exceeded
7. Example of a Fully Structured API User Story
User Story
As a mobile application
I want to retrieve enquiry details by ID via API
So that users can view enquiry information on their mobile devices
Summary
- Create GET endpoint
/api/v1/enquiries/{id}to retrieve enquiry by ID - Implement API key authentication
- Return enquiry data in standardized JSON format
- Handle authentication, authorisation, and not found errors
- Support mobile application integration requirements
Acceptance Criteria
AC1 – Successful enquiry retrieval
Given an enquiry exists with ID 12345
And the enquiry status is AUTHORISED
And the API client has a valid API key
When a GET request is made to /api/v1/enquiries/12345
Then the API returns HTTP status code 200
And the response Content-Type is application/json
And the response body contains JSON:
{
"enquiryId": "12345",
"status": "AUTHORISED",
"customerId": "CUST001",
"vehicleRegistration": "AB12 CDE",
"createdAt": "2025-01-15T10:30:00Z",
"updatedAt": "2025-01-15T14:20:00Z"
}
AC2 – Authentication failure
Given an API request is made to /api/v1/enquiries/12345
When the request does not include authorisation header
Or the API key is invalid
Or the API key has expired
Then the API returns HTTP status code 401
And the response body contains:
{
"error": "Unauthorized",
"message": "Valid API key required",
"code": "AUTH_REQUIRED"
}
And the response includes WWW-Authenticate header
AC3 – Resource not found
Given no enquiry exists with ID 99999
And the API client has valid authentication
When a GET request is made to /api/v1/enquiries/99999
Then the API returns HTTP status code 404
And the response body contains:
{
"error": "Not Found",
"message": "Enquiry with ID 99999 not found",
"code": "ENQUIRY_NOT_FOUND"
}
AC4 – Invalid enquiry ID format
Given the API client has valid authentication
When a GET request is made to /api/v1/enquiries/invalid-id
Then the API returns HTTP status code 400
And the response body contains validation error:
{
"error": "Bad Request",
"message": "Invalid enquiry ID format",
"code": "INVALID_ID_FORMAT"
}
AC5 – Response time performance
Given an enquiry exists with ID 12345
And the API client has valid authentication
When a GET request is made to /api/v1/enquiries/12345
Then the API responds within 200 milliseconds
And the response time is consistent under normal load
AC6 – CORS headers for mobile app
Given a GET request is made to /api/v1/enquiries/12345
When the request includes Origin header from mobile app domain
Then the response includes CORS headers:
- Access-Control-Allow-Origin: [mobile app domain]
- Access-Control-Allow-Methods: GET, OPTIONS
- Access-Control-Allow-Headers: authorisation, Content-Type
API Contract
Endpoint: GET /api/v1/enquiries/{id}
Authentication: API Key (Bearer token in authorisation header)
Request:
GET /api/v1/enquiries/12345 HTTP/1.1
Host: api.example.com
authorisation: Bearer {api_key}
Accept: application/json
Response (200 OK):
{
"enquiryId": "12345",
"status": "AUTHORISED",
"customerId": "CUST001",
"customerName": "ABC Fleet Ltd",
"vehicleRegistration": "AB12 CDE",
"vehicleMake": "Ford",
"vehicleModel": "Transit",
"createdAt": "2025-01-15T10:30:00Z",
"updatedAt": "2025-01-15T14:20:00Z",
"jobLines": [
{
"lineId": "JL001",
"description": "MOT Test",
"status": "COMPLETED",
"amount": 54.99
}
]
}
Error Responses:
401 Unauthorized– Missing or invalid API key404 Not Found– Enquiry ID doesn't exist400 Bad Request– Invalid ID format429 Too Many Requests– Rate limit exceeded500 Internal Server Error– Server error
Dependencies
- Story ABC-123: API authentication service
- Story ABC-124: Enquiry data access layer
- External: API gateway configuration
Notes
- This endpoint is part of API version 1
- Rate limit: 100 requests per minute per API key
- Response caching: 60 seconds for successful responses
- Related design document: [Link to API design doc]
- Postman collection: [Link to Postman collection]
Note: This story must comply with the project's Definition of Done and API standards.
8. API-Specific Considerations
Authentication & authorisation
Every API story must address:
- Authentication method – API key, OAuth, JWT, Basic Auth
- authorisation levels – What permissions are required
- Token validation – How tokens are validated
- Token expiration – Handling expired tokens
AC Example:
Given an API request is made
When the request includes a valid JWT token
And the token has "enquiry:read" permission
Then the API processes the request
And when the token lacks required permission
Then the API returns status 403 Forbidden
Request Validation
API stories must cover:
- Required fields – What fields are mandatory
- Field formats – Data type, format, constraints
- Field lengths – Min/max length validation
- Enum values – Valid value sets
AC Example:
Given a POST request to /api/v1/enquiries
When the request body is missing required field "customerId"
Then the API returns status 400
And the error response lists all missing required fields
And when a field has invalid format (e.g., invalid date)
Then the API returns status 400 with field-specific error
Response Format Standards
Define:
- Status codes – HTTP status code usage
- Response structure – Consistent JSON structure
- Error format – Standardized error response format
- Headers – Required response headers
AC Example:
Given a successful API request
Then the response includes:
- Standard HTTP status code (200, 201, etc.)
- Content-Type: application/json header
- Consistent JSON structure with data/error wrapper
- Timestamp in ISO 8601 format
Error Handling
Cover all error scenarios:
- 4xx Client Errors – Bad requests, unauthorized, not found, etc.
- 5xx Server Errors – Internal errors, service unavailable
- Error response format – Consistent error structure
- Error codes – Application-specific error codes
AC Example:
Given an error occurs during API processing
When the error is a client error (validation, not found)
Then the API returns appropriate 4xx status code
And the error response includes:
- error: error type
- message: human-readable message
- code: application error code
- details: additional error details (if applicable)
Rate Limiting
Define:
- Rate limits – Requests per time period
- Rate limit headers – X-RateLimit-* headers
- Rate limit exceeded response – 429 status handling
AC Example:
Given the API has rate limit of 100 requests per minute
When 100 requests are made within one minute
And another request is attempted
Then the API returns status 429
And the response includes:
- Retry-After header with seconds to wait
- X-RateLimit-Limit header
- X-RateLimit-Remaining header
- X-RateLimit-Reset header
API Versioning
Address:
- Version strategy – URL versioning, header versioning
- Backward compatibility – Breaking vs non-breaking changes
- Deprecation – How deprecated versions are handled
AC Example:
Given API version 2 is released
When a request is made to version 1 endpoint
Then the API continues to support version 1
And when version 1 is deprecated
Then the API returns status 410 Gone
And includes deprecation notice in response
Pagination
For list endpoints:
- Pagination method – Offset-based, cursor-based
- Page size limits – Min/max page sizes
- Pagination metadata – Total count, next/prev links
AC Example:
Given multiple enquiries exist
When a GET request is made to /api/v1/enquiries
Then the API returns paginated results
And the response includes:
- data: array of enquiries
- pagination: { page, pageSize, total, totalPages }
- links: { first, last, next, prev }
9. API Story Anti-Patterns
Missing Authentication
❌ Bad Example:
As a client application
I want to retrieve enquiry data
So that I can display it
(Missing authentication requirements)
✅ Good Example:
As a mobile application
I want to retrieve enquiry data via authenticated API
So that users can securely view enquiry information
(Includes authentication ACs)
Vague Endpoint Definition
❌ Bad Example:
I want an API to get data
(No endpoint, method, or format specified)
✅ Good Example:
I want to retrieve enquiry details via GET /api/v1/enquiries/{id}
So that the mobile app can display enquiry information
(Includes specific endpoint and method)
Missing Error Handling
❌ Bad Example:
Story only covers happy path, no error scenarios
✅ Good Example:
Story includes ACs for:
- Authentication errors
- Validation errors
- Not found errors
- Server errors
No Request/Response Examples
❌ Bad Example:
Story describes endpoint but provides no contract examples
✅ Good Example:
Story includes:
- Request example with headers
- Response example (success)
- Error response examples
- Postman collection reference
10. How to Split Large API Stories
API stories can be split by:
| Technique | Description | Example |
|---|---|---|
| HTTP Methods | Split by operation type | GET, POST, PUT, DELETE |
| Resource endpoints | Split by resource type | /enquiries, /vehicles, /customers |
| Authentication | Split auth from functionality | Auth setup, then endpoints |
| Error handling | Split happy path from errors | Success cases, then error cases |
| API versions | Split by version | v1 endpoints, then v2 endpoints |
| Bulk vs single | Split by operation scope | Single item, then bulk operations |
Example: "Enquiry Management API" can be split into:
- Story 1: GET
/api/v1/enquiries/{id}– Retrieve single enquiry - Story 2: GET
/api/v1/enquiries– List/search enquiries - Story 3: POST
/api/v1/enquiries– Create enquiry - Story 4: PUT
/api/v1/enquiries/{id}– Update enquiry - Story 5: DELETE
/api/v1/enquiries/{id}– Delete enquiry
11. Template for Creating API User Stories
Use this template for new API stories:
## User Story
As a [API consumer - e.g., mobile application, third-party system]
I want to [API operation - e.g., retrieve enquiry details by ID]
So that [business value - e.g., users can view enquiry information]
## Summary
- [Brief bullet point 1 - e.g., Create GET endpoint /api/v1/enquiries/{id}]
- [Brief bullet point 2 - e.g., Implement API key authentication]
- [Brief bullet point 3 - e.g., Return enquiry data in JSON format]
- [Brief bullet point 4 - e.g., Handle authentication and not found errors]
## Acceptance Criteria
### AC1 - [Brief description]
Given [precondition] When [API request is made] Then [expected response] And [additional conditions]
### AC2 - [Brief description]
Given [precondition] When [API request is made] Then [expected response]
## API Contract
**Request:**
[HTTP Method] [Endpoint] HTTP/1.1 [Headers] [Request body if applicable]
**Response (Success):**
```json
{
"example": "response structure"
}
Error Responses:
[Status Code]– [Error description][Status Code]– [Error description]
12. API Story Quality Checklist
Every API story must satisfy:
Story Writing
- Clear API consumer role (not "user" or "developer")
- Specific endpoint and HTTP method defined
- Business value clearly stated
- Summary section with brief bullet points included
API Contract
- Endpoint path clearly defined
- HTTP method specified
- Request format documented (headers, body)
- Response format documented (success and errors)
- Authentication method specified
- authorisation requirements defined
Acceptance Criteria
- Happy path covered
- Authentication failure covered
- authorisation failure covered (if applicable)
- Validation errors covered
- Not found errors covered
- Server errors covered
- Rate limiting covered (if applicable)
- Response time requirements defined
Integration Considerations
- Upstream dependencies identified
- Downstream impacts considered
- API versioning strategy defined
- Backward compatibility addressed
- CORS requirements specified (if web clients)
Documentation
- Request example provided
- Response example provided
- Error response examples provided
- Postman collection or similar reference (if applicable)
13. Conclusion
Well-structured API user stories enable clear integration, reduce development time, and ensure robust API implementations. Following this guide standardizes API story quality across teams and accelerates API delivery.
Key takeaways:
- Contract-first approach – Define API contracts clearly
- Security is mandatory – Authentication and authorisation are not optional
- Comprehensive error handling – Cover all error scenarios
- Clear examples – Request/response examples are essential
- Testability – ACs must enable automated API testing
Use this document as the standard reference for all API story creation in Jira.